home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 4 code / A⁄ROSE / MCPMBƒ / MBTaskSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-27  |  16.9 KB  |  734 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    MBTaskSample.c
  4. #
  5. #    derived from MPW 3.1's "Sample", a MultiFinder-Aware Simple Sample Application
  6. #   - and nearly the same thing as the "TaskSample" in the neighbour folder.
  7. #
  8. #   Launch "MBTaskSample" first, and then "Exercise", and do A/ROSE parallel processing
  9. #   (or rather: Program-to-program communication) even without MCP card!
  10. #
  11. #    Components:
  12. #                MBTaskSample.c
  13. #                MBTaskSample.r
  14. #                MBTaskSample.h
  15. #                ITER16.a
  16. #                MBTaskSample.make
  17. #
  18. #  MPW build commands:
  19. #
  20.         C MBTaskSample.c -r
  21.         Link MBTaskSample.c.o ∂
  22.             ITER16.a.o ∂
  23.             "{CLibraries}"CRuntime.o ∂
  24.             "{CLibraries}"CInterface.o ∂
  25.             "{Libraries}"Interface.o ∂
  26.             ::IPCGlue.o ∂
  27.             -o MBTaskSample 
  28.         Rez -rd -o MBTaskSample MBTaskSample.r -append
  29. #
  30. #
  31. ------------------------------------------------------------------------------*/
  32.  
  33.  
  34.  
  35. #include <Types.h>
  36. #include <Resources.h>
  37. #include <QuickDraw.h>
  38. #include <Fonts.h>
  39. #include <Events.h>
  40. #include <Windows.h>
  41. #include <Menus.h>
  42. #include <TextEdit.h>
  43. #include <Dialogs.h>
  44. #include <Desk.h>
  45. #include <ToolUtils.h>
  46. #include <Memory.h>
  47. #include <SegLoad.h>
  48. #include <Files.h>
  49. #include <OSUtils.h>
  50. #include <OSEvents.h>
  51. #include <DiskInit.h>
  52. #include <Packages.h>
  53. #include <Traps.h>
  54. #include <Strings.h>
  55. #include "MBTaskSample.h"        // bring in all the #defines for MBTaskSample 
  56.  
  57.  
  58. //---------------------------------------------------------------------------
  59. // A/ROSE declarations (from "os.h"):
  60.  
  61. typedef long    tid_type;
  62.  
  63. struct mMessage
  64. {
  65.     struct    mMessage    *mNext;
  66.     long                mId;
  67.     short                mCode;
  68.     short                mStatus;
  69.     unsigned    short    mPriority;
  70.     tid_type            mFrom;
  71.     tid_type            mTo;
  72.     unsigned    long    mSData [3];
  73.     unsigned    long    mOData [3];
  74.     long                mDataSize;        // Size of data buffer in bytes. set to negative 
  75.                                         // size of buffer if buffer is shared
  76.                                         // between tasks. eg. Buffer cannot be copied 
  77.     char                *mDataPtr;
  78. };
  79.  
  80. typedef struct mMessage mMessage;
  81.  
  82. // and #define's from "managers.h":
  83.  
  84. #define    OS_UNKNOWN_MESSAGE        (1<<8)    // unknown message                    
  85. #define    Machine_Visible            0        // Register_task Machine visible flag    
  86. //---------------------------------------------------------------------------
  87.  
  88. // global variables
  89.  
  90. SysEnvRec    gMac;                // set up by Initialize 
  91. Boolean        gHasWaitNextEvent;    // set up by Initialize 
  92. Boolean        gInBackground;        // maintained by Initialize and DoEvent 
  93. long        gSleepVal;            // MultiFinder sleep value
  94.                                 // for WaitNextEvent
  95.  
  96. short        gSent;              // number of received/sent messages 
  97. long        gTID;                // my task identifier returned by OpenQueue() 
  98. WindowPtr    gMyWindow;            // only one window 
  99.  
  100. // Prototypes for parameter type checking. 
  101.  
  102. void EventLoop( void );
  103. void DoEvent( EventRecord *event );
  104. void DoUpdate( WindowPtr window );
  105. void DoActivate( WindowPtr window, Boolean becomingActive );
  106. void DoContentClick( WindowPtr window );
  107. void DrawWindow( WindowPtr window );
  108. void AdjustMenus( void );
  109. void DoMenuCommand( long menuResult );
  110. Boolean DoCloseWindow( WindowPtr window );
  111. void Terminate( void );
  112. void Initialize( void );
  113. void ForceEnvirons( void );
  114. Boolean IsAppWindow( WindowPtr window );
  115. Boolean IsDAWindow( WindowPtr window );
  116. Boolean TrapAvailable( short tNumber, TrapType tType );
  117. void AlertUser( short error );
  118. void BigBadError( short error );
  119. void NumToHex( long n, short d, char *s);
  120. short AROSEPrep();
  121. void TaskProcessing();
  122. void myBitSet(char *pixStorage, long i);
  123.  
  124. extern pascal short ITER16(short cx, short cy, short nmax);
  125.  
  126.  
  127. // A/ROSE prototypes (from "os.h"):
  128.  
  129. extern    tid_type    OpenQueue(void (*)());
  130. extern    void        CloseQueue();
  131. extern    char        Register_Task(char *, char *, short);
  132. extern    void        FreeMsg(mMessage *);
  133. extern    void        Send(mMessage *);
  134. extern    mMessage     *Receive(unsigned long, tid_type, unsigned short, long, ...);
  135. extern    void        SwapTID(mMessage *);
  136. extern     char        *AROSEGetMem();
  137. extern    void        AROSEFreeMem();
  138. extern    short        NetCopy();
  139.  
  140.  
  141.  
  142. extern void _DataInit();
  143.  
  144.  
  145.  
  146. #pragma segment Main
  147. main()
  148. {
  149.     UnloadSeg((Ptr) _DataInit);        // note that _DataInit must not be in Main! 
  150.     
  151.     MaxApplZone();                    // expand the heap so code segments load at the top 
  152.  
  153.     Initialize();                    // initialize the program 
  154.     UnloadSeg((Ptr) Initialize);    // note that Initialize must not be in Main! 
  155.  
  156.     EventLoop();                    // call the main event loop 
  157. }
  158.  
  159.  
  160. #pragma segment Main
  161. void EventLoop()
  162. {
  163.     Boolean        gotEvent;
  164.     EventRecord    event;
  165.  
  166.     do {
  167.             gotEvent = WaitNextEvent(everyEvent, &event, gSleepVal, nil);
  168.         if ( gotEvent )
  169.             DoEvent(&event);
  170.  
  171. //=========================            
  172.         TaskProcessing();  // <<<<<<<<<< this is the A/ROSE task !
  173. //=========================            
  174.         
  175.     } while ( true );    // loop forever; we quit via Terminate/ExitToShell 
  176. } //EventLoop
  177.  
  178.  
  179. #pragma segment Main
  180. void DoEvent(event)
  181.     EventRecord    *event;
  182. {
  183.     short        part, err;
  184.     WindowPtr    window;
  185.     char        key;
  186.     Point        aPoint;
  187.  
  188.     switch ( event->what ) {
  189.         case mouseDown:
  190.             part = FindWindow(event->where, &window);
  191.             switch ( part ) {
  192.                 case inMenuBar:                // process a mouse menu command (if any) 
  193.                     AdjustMenus();
  194.                     DoMenuCommand(MenuSelect(event->where));
  195.                     break;
  196.                 case inSysWindow:            // let the system handle the mouseDown 
  197.                     SystemClick(event, window);
  198.                     break;
  199.                 case inContent:
  200.                     if ( window != FrontWindow() ) {
  201.                         SelectWindow(window);
  202.                     } else
  203.                         DoContentClick(window);
  204.                     break;
  205.                 case inDrag:                // pass screenBits.bounds to get all gDevices 
  206.                     DragWindow(window, event->where, &qd.screenBits.bounds);
  207.                     break;
  208.                 }
  209.             break;
  210.         case keyDown:
  211.         case autoKey:                        // check for menukey equivalents 
  212.             key = event->message & charCodeMask;
  213.             if ( event->modifiers & cmdKey )            // Command key down 
  214.                 if ( event->what == keyDown ) {
  215.                     AdjustMenus();                        // enable/disable/check menu items properly 
  216.                     DoMenuCommand(MenuKey(key));
  217.                 }
  218.             break;
  219.         case activateEvt:
  220.             DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
  221.             break;
  222.         case updateEvt:
  223.             DoUpdate((WindowPtr) event->message);
  224.             break;
  225.         case diskEvt:
  226.             if ( HiWord(event->message) != noErr ) {
  227.                 SetPt(&aPoint, kDILeft, kDITop);
  228.                 err = DIBadMount(aPoint, event->message);
  229.             }
  230.             break;
  231.         case kOSEvent:
  232.             switch ((event->message >> 24) & 0x0FF) {        // high byte of message 
  233.                 case kSuspendResumeMessage:        // suspend/resume is also an activate/deactivate 
  234.                     gInBackground = (event->message & kResumeMask) == 0;
  235.                     DoActivate(FrontWindow(), !gInBackground);
  236.                     break;
  237.             }
  238.             break;
  239.     }
  240. } //DoEvent
  241.  
  242.  
  243. #pragma segment Main
  244. void DoUpdate(window)
  245.     WindowPtr    window;
  246. {
  247.     if ( IsAppWindow(window) ) {
  248.         BeginUpdate(window);                // this sets up the visRgn 
  249.         if ( ! EmptyRgn(window->visRgn) )    // draw if updating needs to be done 
  250.             DrawWindow(window);
  251.         EndUpdate(window);
  252.     }
  253. } //DoUpdate
  254.  
  255.  
  256. #pragma segment Main
  257. void DoActivate(window, becomingActive)
  258.     WindowPtr    window;
  259.     Boolean        becomingActive;
  260. {
  261.     if ( IsAppWindow(window) ) {
  262.         if ( becomingActive )
  263.             ; // do whatever you need to at activation 
  264.         else
  265.             ; // do whatever you need to at deactivation 
  266.     }
  267. } //DoActivate
  268.  
  269. #pragma segment Main
  270. void DoContentClick(window)
  271.     WindowPtr    window;
  272. {
  273. #pragma unused (window)
  274.   // do you want to do something here ? 
  275. } //DoContentClick
  276.  
  277.  
  278. #pragma segment Main
  279. void DrawWindow(window)
  280.     WindowPtr    window;
  281. {
  282.     Str255     s;
  283.     Rect    countRect;
  284.     GrafPtr    savePort;
  285.     short    xPos;
  286.     
  287.     GetPort(&savePort);
  288.     
  289.     SetPort(window);
  290.  
  291.     GetIndString(s, rWndStrings, 1);
  292.     xPos = StringWidth(s) + 10;
  293.     
  294.     SetRect(&countRect, xPos+20, 20, xPos+80, 45);
  295.     EraseRect(&countRect);
  296.  
  297.     MoveTo(20, 40);
  298.     DrawString(s);
  299.  
  300.     MoveTo(xPos+25, 40);
  301.     NumToString(gSent, s);
  302.     DrawString(s);
  303.     
  304.     SetPort(savePort);
  305.  
  306. } //DrawWindow
  307.  
  308.  
  309. #pragma segment Main
  310. void AdjustMenus()
  311. {
  312.     WindowPtr    window;
  313.     MenuHandle    menu;
  314.  
  315.     window = FrontWindow();
  316.  
  317.     menu = GetMHandle(mEdit);
  318.     if ( IsDAWindow(window) ) {        // a desk accessory might need the edit menu… 
  319.         EnableItem(menu, iUndo);
  320.         EnableItem(menu, iCut);
  321.         EnableItem(menu, iCopy);
  322.         EnableItem(menu, iClear);
  323.         EnableItem(menu, iPaste);
  324.     } else {                        // …but we don’t use it 
  325.         DisableItem(menu, iUndo);
  326.         DisableItem(menu, iCut);
  327.         DisableItem(menu, iCopy);
  328.         DisableItem(menu, iClear);
  329.         DisableItem(menu, iPaste);
  330.     }
  331.     menu = GetMHandle(mSleep);
  332.     if (gSleepVal == 0) {
  333.         CheckItem(menu,iNoSleep,true);
  334.         CheckItem(menu,i60Ticks,false);
  335.     }
  336.     else  {
  337.         CheckItem(menu,iNoSleep,false);
  338.         CheckItem(menu,i60Ticks,true);
  339.     }
  340. } //AdjustMenus
  341.  
  342.  
  343. #pragma segment Main
  344. void DoMenuCommand(menuResult)
  345.     long        menuResult;
  346. {
  347.     short        menuID;                // the resource ID of the selected menu 
  348.     short        menuItem;            // the item number of the selected menu 
  349.     short        itemHit;
  350.     Str255        daName;
  351.     short        daRefNum;
  352.     Boolean        handledByDA;
  353.     GrafPtr savePort;
  354.  
  355.     menuID = HiWord(menuResult);    // use macros for efficiency to... 
  356.     menuItem = LoWord(menuResult);    // get menu item number and menu number 
  357.     switch ( menuID ) {
  358.         case mApple:
  359.             switch ( menuItem ) {
  360.                 case iAbout:        // bring up alert for About 
  361.                     itemHit = Alert(rAboutAlert, nil);
  362.                     break;
  363.                 default:            // all non-About items in this menu are DAs 
  364.                     // type Str255 is an array in MPW 3 
  365.                     GetItem(GetMHandle(mApple), menuItem, daName);
  366.                     daRefNum = OpenDeskAcc(daName);
  367.                     break;
  368.             }
  369.             break;
  370.         case mFile:
  371.             switch ( menuItem ) {
  372.                 case iReset:
  373.                     gSent = 0;
  374.                     GetPort(&savePort);        // force redraw
  375.                     SetPort(gMyWindow);
  376.                     InvalRect(&(gMyWindow->portBits.bounds)); 
  377.                     SetPort(savePort);
  378.  
  379.                     break;
  380.                 case iQuit:
  381.                     Terminate();
  382.                     break;
  383.             }
  384.             break;
  385.         case mEdit:                    // call SystemEdit for DA editing & MultiFinder 
  386.             handledByDA = SystemEdit(menuItem-1);    // since we don’t do any Editing 
  387.             break;
  388.         case mSleep:
  389.             switch ( menuItem ) {
  390.                 case iNoSleep:
  391.                     gSleepVal = 0;
  392.                     break;
  393.                 case i60Ticks:
  394.                     gSleepVal = 60;
  395.                     break;
  396.             }
  397.             break;
  398.     }
  399.     HiliteMenu(0);                    // unhighlight what MenuSelect (or MenuKey) hilited 
  400. } //DoMenuCommand
  401.  
  402.  
  403.  
  404. #pragma segment Main
  405. Boolean DoCloseWindow(window)
  406.     WindowPtr    window;
  407. {
  408.     if ( IsDAWindow(window) )
  409.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  410.     else if ( IsAppWindow(window) )
  411.         CloseWindow(window);
  412.     return true;
  413. } //DoCloseWindow
  414.  
  415.  
  416.  
  417. #pragma segment Main
  418. void Terminate()
  419. {
  420.     WindowPtr    aWindow;
  421.     Boolean        closed;
  422.     
  423.     CloseQueue();        // Clean up interaction with A/ROSE Prep 
  424.     closed = true;
  425.     do {
  426.         aWindow = FrontWindow();                // get the current front window 
  427.         if (aWindow != nil)
  428.             closed = DoCloseWindow(aWindow);    // close this window     
  429.     }
  430.     while (closed && (aWindow != nil));
  431.     if (closed)
  432.         ExitToShell();                            // exit if no cancellation 
  433. } //Terminate
  434.  
  435.  
  436.  
  437. #pragma segment Initialize
  438. void Initialize()
  439. {
  440.     Handle        menuBar;
  441.     Ptr            windowP;
  442.     long        total, contig;
  443.     EventRecord event;
  444.     short        count, result;
  445.  
  446.     gInBackground = false;
  447.     gSleepVal = 0;
  448.     gSent = 0;
  449.     
  450.     InitGraf((Ptr) &qd.thePort);
  451.     InitFonts();
  452.     InitWindows();
  453.     InitMenus();
  454.     TEInit();
  455.     InitDialogs(nil);
  456.     InitCursor();
  457.     
  458.     //    This next bit of code is necessary to allow the default button of our
  459.     //    alert be outlined. 
  460.      
  461.     for (count = 1; count <= 3; count++)
  462.         EventAvail(everyEvent, &event);
  463.     
  464.     SysEnvirons(kSysEnvironsVersion, &gMac);
  465.     
  466.     if (gMac.machineType < 0)
  467.         BigBadError(eWrongMachine);
  468.     
  469.     if (! TrapAvailable(_WaitNextEvent, ToolTrap))
  470.         BigBadError(eWrongMachine);
  471.  
  472.     if ((long) GetApplLimit() - (long) ApplicZone() < kMinHeap)
  473.         BigBadError(eSmallSize);
  474.     
  475.     // ZeroScrap(); 
  476.  
  477.     PurgeSpace(&total, &contig);
  478.     if (total < kMinSpace)
  479.         BigBadError(eNoMemory);
  480.  
  481.     result = AROSEPrep();
  482.     if (result != noErr)
  483.         BigBadError(result);
  484.  
  485.     windowP = NewPtr(sizeof(WindowRecord));
  486.     if ( windowP == nil )
  487.         BigBadError(eNoWindow);
  488.  
  489.     gMyWindow = GetNewWindow(rWindow, windowP, (WindowPtr) -1);
  490.     if ( gMyWindow == nil )
  491.         BigBadError(eNoWindow);
  492.  
  493.     menuBar = GetNewMBar(rMenuBar);            // read menus into menu bar 
  494.     if ( menuBar == nil )
  495.         BigBadError(eNoMemory);
  496.     SetMenuBar(menuBar);                    // install menus 
  497.     DisposHandle(menuBar);
  498.     AddResMenu(GetMHandle(mApple), 'DRVR');    // add DA names to Apple menu 
  499.     DrawMenuBar();
  500.     
  501. } //Initialize
  502.  
  503.  
  504. #pragma segment Main
  505. Boolean IsAppWindow(window)
  506.     WindowPtr    window;
  507. {
  508.     short        windowKind;
  509.  
  510.     if ( window == nil )
  511.         return false;
  512.     else {    // application windows have windowKinds = userKind (8) 
  513.         windowKind = ((WindowPeek) window)->windowKind;
  514.         return (windowKind = userKind);
  515.     }
  516. } //IsAppWindow
  517.  
  518.  
  519. #pragma segment Main
  520. Boolean IsDAWindow(window)
  521.     WindowPtr    window;
  522. {
  523.     if ( window == nil )
  524.         return false;
  525.     else    // DA windows have negative windowKinds 
  526.         return ((WindowPeek) window)->windowKind < 0;
  527. } //IsDAWindow
  528.  
  529.  
  530. #pragma segment Initialize
  531. Boolean TrapAvailable(tNumber,tType)
  532.     short        tNumber;
  533.     TrapType    tType;
  534. {
  535.     if ( ( tType == ToolTrap ) &&
  536.         ( gMac.machineType > envMachUnknown ) &&
  537.         ( gMac.machineType < envMacII ) ) {        // it's a 512KE, Plus, or SE 
  538.         tNumber = tNumber & 0x03FF;
  539.         if ( tNumber > 0x01FF )                    // which means the tool traps 
  540.             tNumber = _Unimplemented;            // only go to 0x01FF 
  541.     }
  542.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  543. } //TrapAvailable
  544.  
  545.  
  546. #pragma segment Main
  547. void AlertUser( short error)
  548. {
  549.     short        itemHit;
  550.     Str255        errMsg;
  551.  
  552.     SetCursor(&qd.arrow);
  553.     if ((error>0)&&(error<=kLastErrStr)) {
  554.         GetIndString(errMsg, rErrStrings, error);
  555.         ParamText(errMsg, "", "", "");
  556.     }
  557.     else {
  558.         NumToString(error, &errMsg);
  559.         ParamText("\pUnknown error", errMsg, "", "");
  560.     }
  561.         
  562.     itemHit = Alert(rUserAlert, nil);
  563. } // AlertUser 
  564.  
  565. #pragma segment Main
  566. void BigBadError( short error)
  567. {
  568.     AlertUser(error);
  569.     if (gTID>0)
  570.         CloseQueue();
  571.     ExitToShell();
  572. }
  573.  
  574.  
  575. #pragma segment Main
  576. void NumToHex( long n, short d, char *s)   // I hate this @#%@ !
  577.     // s must point to at least d+1 free bytes - returns Pascal String of length d
  578.     // requires d > 0
  579. {
  580.     short c;
  581.     
  582.     s[0] = d;
  583.     do {
  584.         c =  (n & 0x0F) + 48;    // not so Script Manager compatible
  585.                                 // (as usual at this programming level...)
  586.         if (c>57)
  587.             c = c+7;
  588.         s[d--] = (char) c;
  589.         n = n>>4;
  590.     } while (d > 0);
  591. }
  592.  
  593. #pragma segment Main
  594. void StringCopy(char *s, char *t)
  595. {
  596.     short n= (*t++ = *s++);
  597.     while (n-- >0)
  598.         *t++ = *s++;
  599. }
  600.  
  601. #pragma segment Initialize
  602. short AROSEPrep()
  603. {
  604.     StringHandle sh;
  605.     Str255 taskName = "?", taskType = "?";
  606.  
  607.     sh = GetString(rTaskName);
  608.     if (sh != nil)
  609.         StringCopy(*sh,taskName);
  610.     sh = GetString(rTaskType);
  611.     if (sh != nil)
  612.         StringCopy(*sh,taskType);
  613.     
  614.     gTID = OpenQueue(0);
  615.     if (gTID == 0) {
  616.         return(eNoAROSE);
  617.     }
  618.     if (!Register_Task (p2cstr(&taskName), p2cstr(&taskType), Machine_Visible)) {
  619.         CloseQueue(); // better clean up - we are going to Exit 
  620.         return(eRegister);
  621.     }
  622.     return(noErr);
  623. }
  624.  
  625.  
  626. #pragma segment Main
  627. void TaskProcessing()
  628.     
  629. // the only differences between an A/ROSE task and a .IPC process under MacOS are:
  630. // 1) a 5th parameter in Receive (here =nil: no completion routine)
  631. // 2) replace OS_NO_TIMEOUT (4th parameter) by -1L = "return immediately"
  632. //       with m = nil or  mMessage *m
  633. // 3) add a test on (m == 0)
  634. // 4) some minor adaptations in the declaration of variables
  635. //    and in the initialisation
  636. //-------------------------------------------------------------------------
  637. {
  638. struct MBparms {
  639.     short        nmax;        // max. depth of iteration
  640.     short        d;            // corresponding to coord. distance between pixels
  641.     short        cx, cy;        // current point of the complex plane to be computed
  642.     short        yMCP;        // line number (to be sent back to server)
  643.     };
  644.  
  645.     struct MBparms MBp;        // these are the first 8 bytes of MBvariables, passed
  646.                             // along in m->mSData[0..1];
  647.     short  pixcnt, i;
  648.     mMessage *m;
  649.     char     *pixStorage, *p;
  650.     GrafPtr savePort;
  651.     
  652.     
  653.     m = Receive(0L, 0L, 0L, -1L, nil);  // -1L: return without waiting (OS_NO_TIMEOUT)
  654.                                         // nil: no completion routine
  655.                                         
  656. // in A/ROSE this would be:    m = Receive(OS_MATCH_ALL, OS_MATCH_ALL, OS_MATCH_ALL, OS_NO_TIMEOUT);
  657.  
  658.     if (m) {
  659.  
  660.         if (m->mStatus != 0)     {    // message was considered undeliverable
  661.             AlertUser(eUndeliverable);
  662.             FreeMsg(m);                // of no use any more: give it back to A/ROSE
  663.         }
  664.         else {
  665.             switch (m->mCode)    {
  666.             case MBCODE:
  667.                     BlockMove((char *)&m->mSData[0], (char *)&MBp, 12);
  668.                     pixcnt = 8 * m->mDataSize;
  669.                     p = AROSEGetMem(m->mDataSize);
  670.                     if (p) {
  671.                         pixStorage = p;
  672.                         for (i=0; i<m->mDataSize; i++) *p++ = 0; // clear it out
  673.                         for (i=0; i<pixcnt; i++) {
  674.                             if (ITER16(MBp.cx, MBp.cy, MBp.nmax) & 0x1)    // compute fancy pattern
  675.                                 myBitSet(pixStorage, i);
  676.                             MBp.cx += MBp.d;
  677.                         }
  678.                         m->mOData[0] = MBp.yMCP;
  679.                         m->mCode++;            // and send it back
  680.                         SwapTID(m);
  681.                         NetCopy(m->mFrom, pixStorage, m->mTo, m->mDataPtr, m->mDataSize);
  682.                         Send (m);
  683.                         AROSEFreeMem(pixStorage);
  684.                          gSent++;        // update counter display
  685.                     }
  686.                     else {
  687.                         AlertUser(eAROSEMemErr);
  688.                         m->mCode++;            // send it back anyway
  689.                         SwapTID(m);
  690.                         Send (m);
  691.                     }
  692.  
  693.                     break;
  694.                 
  695.             default:
  696.                     AlertUser(eUnknownMsg);
  697.                     m->mCode++;
  698.                     m->mCode |= 0x8000;    // unrecognized message code;
  699.                     m->mStatus = OS_UNKNOWN_MESSAGE; // defined in "managers.h"
  700.                     SwapTID(m);
  701.                     Send (m);
  702.                         
  703.                     break;
  704.                     
  705.             }
  706.             
  707.             GetPort(&savePort);
  708.             SetPort(gMyWindow);
  709.             
  710.             InvalRect(&(gMyWindow->portBits.bounds)); 
  711.             
  712.             SetPort(savePort);
  713.             
  714.         } // message OK
  715.         
  716.     } // a message arrived
  717. }
  718.  
  719.  
  720.  
  721. void myBitSet(char *pixStorage, long i)
  722. {
  723.     long offset;
  724.     short bitnb;
  725.     char abyte, *p;
  726.     
  727.     offset = (i >> 3);  // divide /8
  728.     bitnb  = i - 8*offset;
  729.     abyte = 0x80 >> bitnb;
  730.     p = pixStorage + offset;
  731.     *p = *p | abyte;
  732. }
  733.  
  734.